package k8.text;

import k8.k8;
import k8.SceneNode;
import k8.primitive.Triangle;
import k8.util.LinkedList;

/** Represents a text layout. */
public class Text extends SceneNode
{

	public static Font newTextFont;

	private static LinkedList.Node<Triangle> curr;

	/** Sets the default font assigned to new Text instances. */
	public static void setDefaultFont(String font)
	{
		try
		{
			newTextFont = new Font(font);
		}
		catch (Exception e)
		{
			k8.logger.warning("Can't set default Text Font to " + font);
			k8.logger.warning(e.getMessage());
		}
	}

	private String text;

	private Font font;

	private float scale;

	private float x, w, a, d;

	private int c, l;

	private GlyphMetrics gm;

	private LinkedList<Triangle> triangles;

	/**
	 * Creates a new instance of Text.
	 * 
	 * @throws Exception
	 */
	public Text()
	{
		this("");
	}

	/**
	 * Creates a new instance of Text.
	 * 
	 * @throws Exception
	 */
	public Text(String text)
	{
		this(text, 1);
	}

	/**
	 * Creates a new instance of Text.
	 * 
	 * @throws Exception
	 */
	public Text(String text, float scale)
	{
		if (newTextFont == null)
		{
			setDefaultFont("/k8/text/Default.png");
		}
		this.font = newTextFont;
		triangles = new LinkedList<Triangle>();
		setScale(scale);
		setText(text);
	}

	public void setFont(Font font)
	{
		this.font = font;
		update();
	}

	public void setText(int text)
	{
		setText(Integer.toString(text));
	}

	public void setText(long text)
	{
		setText(Long.toString(text));
	}

	public void setText(String text)
	{
		this.text = text;
		if (text != null && text.length() > 0)
		{
			update();
		}
	}

	public void setScale(float scale)
	{
		this.scale = scale;
	}

	/** Updates/Adds/Removes triangles to display a change in text. */
	private void update()
	{
		// Avoid updating when there is no font or text
		if (font == null || text == null || text.equals(""))
			return;

		// Setup counters
		x = 0;
		c = 0;
		l = text.length();

		// Reuse previous triangles
		curr = null;
		while ((curr = triangles.next(curr)) != null)
		{
			// Hide remaining triangles
			if (c == l)
			{
				curr.item.setVisible(false);
				continue;
			}

			// Reuse current and next triangle for current character
			gm = font.getGlyphMetrics(text.codePointAt(c));

			// Apply scaling
			w = gm.width * scale;
			a = gm.ascent * scale;
			d = gm.descent * scale;

			// ._
			// | /
			// |/
			curr.item.setVertices(x, a, 0, x, d, 0, x + w, a, 0);
			curr.item.setTexture(gm.u1, gm.v1, gm.u1, gm.v2, gm.u2, gm.v1);
			curr.item.setVisible(true);

			// Advance to next Triangle
			curr = triangles.next(curr);

			// ./|
			// /_|
			curr.item.setVertices(x, d, 0, x + w, d, 0, x + w, a, 0);
			curr.item.setTexture(gm.u1, gm.v2, gm.u2, gm.v2, gm.u2, gm.v1);
			curr.item.setVisible(true);

			// Advance next position width of current character
			x += w;
			c++;
		}

		// Create new triangles, when needed, for remaining characters
		while (c < l)
		{
			// Get the GlyphMetrics for the current character
			gm = font.getGlyphMetrics(text.codePointAt(c));

			// Apply scaling
			w = gm.width * scale;
			a = gm.ascent * scale;
			d = gm.descent * scale;

			// Create two new triangles, set attributes and add

			// ._
			// | /
			// |/
			Triangle t = new Triangle();
			t.setTexture(font);
			t.setVertices(x, a, 0, x, d, 0, x + w, a, 0);
			t.setTexture(gm.u1, gm.v1, gm.u1, gm.v2, gm.u2, gm.v1);
			this.add(t);
			triangles.append(t);

			// ./|
			// /_|
			t = new Triangle();
			t.setTexture(font);
			t.setVertices(x, d, 0, x + w, d, 0, x + w, a, 0);
			t.setTexture(gm.u1, gm.v2, gm.u2, gm.v2, gm.u2, gm.v1);
			this.add(t);
			triangles.append(t);

			// Advance next position width of current character
			x += w;
			c++;
		}
	}

	@Override
	protected void transform()
	{
		// TODO Auto-generated method stub
	}

}
